#include <mqueue.h>    // 引入消息队列相关头文件
#include <stdio.h>     // 引入标准输入输出头文件
#include <pthread.h>   // 引入线程库头文件
#include <unistd.h>    // 引入Unix标准定义的常用函数，如sleep等
#include <string.h>    // 引入字符串处理库

//* 命名规则：必须是以正斜杠/开头，以\0结尾的字符串，中间可以包含若干字符，但不能有正斜杠
static char *mq_name = "/test_mq"; // 消息队列的名字, 以"/"开头，代表系统中的消息队列名
static mqd_t mq_fd; // 队列文件的文件描述符，mqd_t 是一个代表消息队列的类型 相当于句柄

// 第一个线程函数
void *first_thread_fun(void *arg)
{
    sleep(1); // 休眠1秒，确保第二个线程有时间准备好
    printf("first线程执行, 准备发送消息 \n");
    char *data = "atguigu"; // 待发送的消息内容
    // 发送消息到消息队列，消息大小为 strlen(data) + 1 (包括结束符)
    //为沙加1 ：因为strlen函数计算的是字符串的长度，不包括字符串结束符'\0'，而mq_send函数需要发送的长度包括结束符'\0'，所以需要加1。
    // 第四个参数是消息的优先级，这里设置为1
    mq_send(mq_fd, data, strlen(data) + 1, 1);
    return NULL;
}

// 第二个线程函数
void *second_thread_fun(void *arg)
{
    printf("second线程执行, 准备接收消息 \n");
    char buf[100]; // 接收消息的缓冲区，长度至少为消息的最大长度，这里设置为100
    // 接收消息，如果队列没有消息，则该调用会阻塞，直到有消息为止
    // 这里接收到的消息将存储在 buf 中，返回的 len 是接收到的消息的实际字节数
    ssize_t len = mq_receive(mq_fd, buf, sizeof(buf), NULL);
    // 输出接收到的消息和消息的长度
    printf("接收到的消息是: %.*s, 长度是: %ld\n", (int)len, buf, len);

    return NULL;
}

int main(int argc, char const *argv[])
{
    printf("主线程开始执行\n");

    // 创建消息队列的属性设置
    struct mq_attr attr;
    attr.mq_maxmsg = 10; // 消息队列中最多可存储的消息个数
    attr.mq_msgsize = 100; // 每条消息的最大字节数
    // 使用 O_CREAT 表示如果消息队列不存在，则创建；O_RDWR 表示读写权限
    // 0644 是权限，表示所有者可读写，其他用户只能读
    mq_fd = mq_open(mq_name, O_CREAT | O_RDWR, 0644, &attr);
    if (mq_fd == -1)
    {
        printf("创建消息队列失败\n");
        return -1; // 如果消息队列创建失败，打印错误并退出
    }

    pthread_t pt1, pt2; // 定义两个线程变量
    // 创建第一个线程，执行第一个线程函数
    pthread_create(&pt1, NULL, first_thread_fun, NULL);
    // 创建第二个线程，执行第二个线程函数
    pthread_create(&pt2, NULL, second_thread_fun, NULL);
    
    // 等待第一个线程执行完毕
    pthread_join(pt1, NULL);
    // 等待第二个线程执行完毕
    pthread_join(pt2, NULL);

    // 关闭消息队列
    mq_close(mq_fd);
    // 删除消息队列
    mq_unlink(mq_name);

    return 0;
}
